package dabs.engine;

import static org.junit.Assert.*;

import java.util.ArrayList;

import javax.swing.text.html.HTMLEditorKit.Parser;

import org.junit.Before;
import org.junit.Test;

import dabs.engine.control.ComponentCommand;
import dabs.engine.control.GameCommand;
import dabs.engine.environment.Environment;
import dabs.engine.exceptions.ComponentNotFoundException;
import dabs.engine.exceptions.UnknownGameCommand;
import dabs.engine.plant.ComponentPart;
import dabs.engine.plant.Condenser;
import dabs.engine.plant.HydraulicProperty;
import dabs.engine.plant.HydraulicState;
import dabs.engine.plant.PowerPlant;
import dabs.engine.plant.Pump;
import dabs.engine.plant.Reactor;
import dabs.engine.plant.Valve;
import dabs.ginterface.CommandParser;

public class EngineTest {

	GameEngine geng;
	DummyInterface dinterface;
	ArrayList<Integer> list;
	ArrayList<Integer> list2;
	CommandParser parser;
	ArrayList<String> args;
	ArrayList<String> args2;	
	
	@Before
	public void setUp() throws Exception {
		geng = new GameEngine();
		dinterface = new DummyInterface();		
		geng.registerInterface(dinterface);		
		list = new ArrayList<Integer>();
		list2 = new ArrayList<Integer>();		
		parser = new CommandParser();	
		 args = new ArrayList<String>();
		 args2 = new ArrayList<String>();
	}
	
	
	@Test
	public void testSaveandLoad() throws Exception {
	
	ArrayList<String> state = new ArrayList<String>();
		ArrayList<String> state2 = new ArrayList<String>();	
		ArrayList<Boolean> isdeactivated = new ArrayList<Boolean>();
		ArrayList<Boolean> isdeactivated2 = new ArrayList<Boolean>();
		args.add("10");
		args2.add("close");
		PowerPlant plant = new PowerPlant(dinterface);
			
		
		//start the game 
		geng.runCommand(new GameCommand("name Sth"));
		geng.runCommand(new GameCommand("start"));
		//to test if saving overrides the previous save, save at the begining of game
		//and later the save will be repeated, expected values - from second save
		geng.runCommand(new GameCommand("save"));  

		
		//ticking to get things changing
		for(int j = 0; j<62; ++j) {
			geng.tick();}
				
		geng.runCommand(new GameCommand("save"));  
		// make lists for component attributes before saving		
		for (ComponentPart comp : plant.getComponents()){
			list.add(comp.getHealth());	
			list.add(comp.getPressure());
			state.add(comp.getNewHydroState().toString());
							
				//to check for all the components if they are deactivated - if they can not change 
				//their values, and give a message of stalling, then they're deactivated
				if(comp instanceof Reactor || comp instanceof Pump || comp instanceof Condenser){
				dinterface.makeEmpty();
				ComponentCommand command = new ComponentCommand(comp.getName(), args);
				comp.runCommand(command);
				isdeactivated.add(dinterface.toString().contains("stalled"));				
				}
				
				if(comp instanceof Valve){
					dinterface.makeEmpty();
					ComponentCommand command = new ComponentCommand(comp.getName(), args2);
					comp.runCommand(command);									
					isdeactivated.add(dinterface.toString().contains("blocked"));					
				}
		} 		
		
	//	geng.runCommand(new GameCommand("save"));
		
		//wait some time before loading
		for(int j = 0; j<3; ++j) {
			geng.tick();}
		
		geng.runCommand(new GameCommand("load"));
		
		//make lists of component attributes after loading
		 for (ComponentPart comp : plant.getComponents()){
		list2.add(comp.getHealth());
		list2.add(comp.getPressure());
		state2.add(comp.getNewHydroState().toString()); 
		
		if(comp instanceof Reactor || comp instanceof Pump || comp instanceof Condenser){
			dinterface.makeEmpty();
			ComponentCommand command = new ComponentCommand(comp.getName(), args);
			comp.runCommand(command);
			isdeactivated2.add(dinterface.toString().contains("stalled"));				
			}
			
			if(comp instanceof Valve){
				dinterface.makeEmpty();
				ComponentCommand command = new ComponentCommand(comp.getName(), args2);
				comp.runCommand(command);									
				isdeactivated2.add(dinterface.toString().contains("blocked"));					
			}		
		 }
		 	
		System.out.println(list);
		System.out.println(list2);
		assertEquals("Is the state of Health and Preassure the same before saving and after loading",list, list2);
		assertEquals("Are Hydraulic states the same",state, state2);
		assertEquals("Are all the components that were deactivated still deactivated",isdeactivated, isdeactivated2);			
	}  
	
	@Test
	public void testIfEverythingTicks() {
		geng.tick();
		geng.tick();
		assertEquals(2, geng.getValue());
		assertEquals(2,geng.getEnvironment().getTiked());
		for(ComponentPart comp : geng.getPowerPlant().getComponents()){
			assertEquals(2,comp.getTicked());
		}	
	}
	
	@Test
	public void testNotification() {
		geng.tick();
		geng.getEnvironment().generateDisable(10);
		System.out.println(dinterface);
		assertTrue(dinterface.toString().contains("stalling in")||dinterface.get().getDescription().contains("blocked"));
	} 

	@Test 
	public void testThatGameFails(){
		//ToBe expanded a lot 
	
		for (ComponentPart comp : geng.getPowerPlant().getComponents()){
		list.add(comp.getHealth());		
		}  			
		for(int i = 0; i<10000; ++i) {
		geng.tick();}	
		
		for (ComponentPart comp : geng.getPowerPlant().getComponents()){
		list2.add(comp.getHealth());}	
		assertFalse(list.equals(list2));	
		assertEquals(geng.getState().toString(),"GameOver");
		
	}
	
	
	
	@Test (expected= IndexOutOfBoundsException.class)
	public void testException() {
		geng.getPowerPlant().getComponents().get(100);
	}

	@Test
	public void testGameStates() throws UnknownGameCommand, ComponentNotFoundException{
		//try running commands and see if the state of the game is chageing as it's supposed to
		assertEquals(geng.getState().toString(),"Intro");
		geng.runCommand(new GameCommand("name Sth"));
		assertEquals(geng.getState().toString(),"Intro");
		//check invalid command - the state of game doesn't change
		geng.runCommand(new GameCommand("Sth"));
		assertEquals(geng.getState().toString(),"Intro");		
		geng.runCommand(new GameCommand("activate"));
		assertEquals(geng.getState().toString(),"Running");	
		geng.runCommand(new GameCommand("save"));
		assertEquals(geng.getState().toString(),"Running");
		geng.runCommand(new GameCommand("pause"));
		assertEquals(geng.getState().toString(),"Paused");	
		geng.runCommand(new GameCommand("resume"));
		assertEquals(geng.getState().toString(),"Running");
		geng.getPowerPlant().getComponent("turbine").setHealth(0);	
		// turbine dies - a tick() has to pass for everything to 
		//know that the game is over
		geng.tick();
		assertEquals(geng.getState().toString(),"GameOver");
		//after the game is over - it can be loaded, and loads in a pause state
		geng.runCommand(new GameCommand("load"));
		assertEquals(geng.getState().toString(),"Paused");
		
	}
	
	@Test
	public void testInfoWhenDead() throws ComponentNotFoundException, UnknownGameCommand {
		geng.runCommand(new GameCommand("name Sth"));
		geng.runCommand(new GameCommand("start"));
		geng.tick();
		geng.tick();   
		
		assertFalse((geng.getPowerPlant().isDead()));		
		geng.getPowerPlant().getComponent("turbine").setHealth(0);	
		dinterface.makeEmpty();
		geng.tick();
		assertTrue((geng.getPowerPlant().isDead()));
		
		// the player is informed about the end of the game
		assertTrue(dinterface.toString().contains("BOOOOOOOOOOOOOOOOOOOOOOOOM"));
		assertTrue(dinterface.toString().contains("Game over"));		
		int score = geng.getPowerPlant().getScore();
		String scoore = String.valueOf(score);		
		//the score of the game is provided for the player
		assertTrue(dinterface.toString().contains(scoore));			
	} 	
	
}
